package com.example.springvue.common.aop;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.springvue.common.annotation.LogAnnotation;
import com.example.springvue.common.handler.AdminUserHeaderHodler;
import com.example.springvue.common.handler.NotExistException;
import com.example.springvue.common.utils.CommonUtils;
import com.example.springvue.model.AdminLog;
import com.example.springvue.model.AdminUser;
import com.example.springvue.service.AdminLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

@Component
@Aspect
public class AopAspect {
    @Resource
    AdminLogService adminLogService;


    //需要切入的注解
    @Pointcut("@annotation(com.example.springvue.common.annotation.LogAnnotation)")
    public void pointcut(){

    }

    //环绕通知
    @Around("pointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint)throws NotExistException {
        try {
            long beginTime = System.currentTimeMillis();
            //执行方法
            Object result = joinPoint.proceed();
            //执行时长（毫秒）
            long time = System.currentTimeMillis() - beginTime;
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);
            //获取注解的内容
            String logAnnotations = logAnnotation.operator();
            String modelName = logAnnotation.module();
            if (!logAnnotations.equals("") && !modelName.equals("")){
                AopLog(joinPoint,time);
            }
            //保存日志
            return result;
        }catch (Throwable throwable){
            throwable.printStackTrace();
            throw new NotExistException("方法执行发生异常");
        }
    }
    public void AopLog(ProceedingJoinPoint joinPoint,Long time){
        // 获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes
                .resolveReference(RequestAttributes.REFERENCE_REQUEST);

        String Ip = CommonUtils.getIpAddr(request);

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);
        //获取注解的内容
        String logAnnotations = logAnnotation.operator();
        String modelName = logAnnotation.module();

        AdminUser adminUser = AdminUserHeaderHodler.get();


        AdminLog adminLog = new AdminLog();
        if (CommonUtils.isNotEmptyObject(adminUser)) {
            adminLog.setAdminId(adminUser.getId());
            adminLog.setAdminName(adminUser.getNickname());//操作者账号
        }
        adminLog.setClassName(joinPoint.getTarget().getClass().getName()); //类名
        adminLog.setParameter(getParams(joinPoint));//请求参数
        adminLog.setOperationName(logAnnotations);//操作名称（自定义的注解）
        adminLog.setModelName(modelName);//模块名称（自定义的注解参数）
        adminLog.setMethodName(joinPoint.getSignature().getName()); //方法名称
        adminLog.setIp(Ip);//发起请求的ip地址
        adminLog.setUrl(request.getRequestURI());//请求的url
        adminLog.setStatus(1);//请求状态 1为正常，2为异常
        adminLog.setTime(Math.toIntExact(time));
        //记录操作日志
        adminLogService.Add(adminLog);

    }
    //前置通知
    @Before("pointcut()")
    public void before(JoinPoint joinPoint){
    }

    //后置通知
    @After("pointcut()")
    public void after(JoinPoint joinPoint){
    }

    //返回通知
    @AfterReturning("pointcut()")
    public void afterReturning(JoinPoint joinPoint){
    }

    //异常通知通知
    @AfterThrowing(pointcut = "pointcut() ", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Throwable e){
        // 获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes
                .resolveReference(RequestAttributes.REFERENCE_REQUEST);

        String Ip = CommonUtils.getIpAddr(request);

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        LogAnnotation logAnnotation = method.getAnnotation(LogAnnotation.class);
        //获取注解的内容
        String logAnnotations = logAnnotation.operator();
        String modelName = logAnnotation.module();
        AdminUser adminUser = AdminUserHeaderHodler.get();
        AdminLog adminLog = new AdminLog();
        if (CommonUtils.isNotEmptyObject(adminUser)) {
            adminLog.setAdminId(adminUser.getId());
            adminLog.setAdminName(adminUser.getNickname());//操作者账号
        }
        adminLog.setClassName(joinPoint.getTarget().getClass().getName()); //类名
        adminLog.setParameter(getParams(joinPoint));//请求参数
        adminLog.setOperationName(logAnnotations);//操作名称（自定义的注解）
        adminLog.setModelName(modelName);//模块名称（自定义的注解参数）
        adminLog.setMethodName(joinPoint.getSignature().getName()); //方法名称
        adminLog.setIp(Ip);//发起请求的ip地址
        adminLog.setUrl(request.getRequestURI());//请求的url
        adminLog.setStatus(2);//请求状态 1为正常，2为异常
        adminLog.setThrowing(stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace()));
        //记录操作日志
        adminLogService.Add(adminLog);

    }



    /**
     * 转换异常信息为字符串
     *
     * @param exceptionName    异常名称
     * @param exceptionMessage 异常信息
     * @param elements         堆栈信息
     */
    public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
        StringBuffer strbuff = new StringBuffer();
        for (StackTraceElement stet : elements) {
            strbuff.append(stet + "\n");
        }
        String message = exceptionName + ":" + exceptionMessage + "\n\t" + strbuff.toString();
        return message;
    }

    //请求参数
    private String getParams(JoinPoint joinPoint) {
        String params = "";
        if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
            for (int i = 0; i < joinPoint.getArgs().length; i++) {
                Object arg = joinPoint.getArgs()[i];
                if ((arg instanceof HttpServletResponse) || (arg instanceof HttpServletRequest)
                        || (arg instanceof MultipartFile) || (arg instanceof MultipartFile[])) {
                    continue;
                }
                try {
//                    System.out.println("日志"+joinPoint.getArgs()[i]);
                    params += JSONObject.toJSONString(joinPoint.getArgs()[i]);
                } catch (Exception e1) {

                }
            }
        }
        return params;
    }
}
